package haizhi.fruitmall.shiro.realm;

import haizhi.fruitmall.pojo.po.User;
import haizhi.fruitmall.service.UserService;

import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

public class UserRealm extends AuthorizingRealm {

	@Resource
	private UserService userService;

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		// 把 AuthenticationToken 转换为 UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;

		// 从 UsernamePasswordToken 中来获取 username
		String user_name = upToken.getUsername();
		// 从UsernamePasswordToken 中来获取password

		// 调用数据库的方法, 从数据库中查询 username 对应的用户记录
		String user_password = "";

		List<User> userList = userService.getUserByUserName(user_name);
		if (userList.size() == 0) {
			throw new UnknownAccountException();// 没找到帐号
		} else {
			user_password = userList.get(0).getUserPassword();
		}

		// 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为:
		// SimpleAuthenticationInfo
		// 1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
		Object principal = user_name;
		// 2). credentials: 密码.
		Object credentials = user_password;

		// 3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
		String realmName = getName();

		// 4). 盐值.盐值需要唯一，一般使用随机字符串或user id
		ByteSource credentialsSalt = ByteSource.Util.bytes(user_name);

		SimpleAuthenticationInfo info = null;

		// 计算盐值加密后的密码的值
		info = new SimpleAuthenticationInfo(principal, credentials,
				credentialsSalt, realmName);

		return info;
	}

	// 授权会被 shiro 回调的方法
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// 1. 从 PrincipalCollection 中来获取登录用户的信息
		String user_name = (String) principals.getPrimaryPrincipal();

		// 2. 利用登录的用户的信息来配置当前用户的角色或权限(可能需要查询数据库)

		// 3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性.
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setRoles(userService.getUserRoleSet(user_name));
		info.setStringPermissions(userService.getUserAuthSet(user_name));

		// 4. 返回 SimpleAuthorizationInfo 对象.
		return info;
	}
}
